﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using SharedGenomics.Core;
using SharedGenomics.Core.Collections;
using SharedGenomics.Annotations;
using SharedGenomics.Workbench.Annotations;
using SharedGenomics.Workbench.Tests.TestObjects;

namespace SharedGenomics.Workbench.Tests.Annotations
{
    [TestClass]
    public class AnnotationPlanRunnerTests
    {
        private StaticAnnotationPlan plan;
        private AnnotationPlanRunner planRunner;
        private AnnotationInfoSet annotations;

        [TestInitialize]
        public void Setup()
        {
            TreeNode<AnnotationKey> root = new TreeNode<AnnotationKey>(null);
            Tree<AnnotationKey> planTree = new Tree<AnnotationKey> { Root = root };
            var googleNode = root.AddChild(AnnotationKey.GoogleSearch);
            var ncbiNode = root.AddChild(AnnotationKey.NcbiSummary);
            var publicationsNode = ncbiNode.AddChild(AnnotationKey.Publications);
            var pubMedNode = ncbiNode.AddChild(AnnotationKey.PubMedSearch);

            this.plan = new StaticAnnotationPlan(planTree);

            var descriptors = this.GetTestKeys().Select(key => AnnotationDescriptor.GetDescriptorForKey(key));
            this.annotations = new AnnotationInfoSet(new AnnotationValue(AnnotationKey.SnpName, "rs1"), descriptors);
            this.planRunner = new AnnotationPlanRunner(annotations, new TestAnnotationRequestQueue());
        }

        [TestMethod]
        public void ShouldCompletePlan()
        {
            planRunner.Run(plan);

            var googleResult = new SucceededAnnotationRequestResult(AnnotationKey.GoogleSearch, "rs1", new GoogleSearchAnnotation("rs1"), null);
            planRunner.Notify(googleResult);

            var ncbiAnnotation = new NcbiAnnotation("organism", "rs1", 123, new[] { "gene1" }, 4, 10000);
            var ncbiResult = new SucceededAnnotationRequestResult(AnnotationKey.NcbiSummary, "rs1", ncbiAnnotation, new[] { new AnnotationValue(AnnotationKey.EntrezGeneId, 123) });
            planRunner.Notify(ncbiResult);

            var pubMedResult = new SucceededAnnotationRequestResult(AnnotationKey.PubMedSearch, "rs1", new PubMedSearchAnnotation(123), null);
            planRunner.Notify(pubMedResult);

            PublicationsAnnotation publicationsAnnotation = new PublicationsAnnotation(new List<SharedGenomics.Domain.Publication>());
            var publicationsResult = new SucceededAnnotationRequestResult(AnnotationKey.Publications, "rs1", publicationsAnnotation, null);
            planRunner.Notify(publicationsResult);

            //all annotations should be completed
            this.GetTestKeys()
                .Select(key => annotations[key])
                .ForEach(info => Assert.AreEqual(AnnotationRequestStatus.Finished, info.Status));

            Assert.IsTrue(plan.IsComplete);
        }

        [TestMethod]
        public void ShouldFailDependentRequests()
        {
            this.planRunner.Run(this.plan);

            var googleResult = new SucceededAnnotationRequestResult(AnnotationKey.GoogleSearch, "rs1", new GoogleSearchAnnotation("rs1"), null);
            planRunner.Notify(googleResult);

            //fail ncbi request - this should mean that the dependet publications and pubmed search annotations also fail
            var ncbiResult = new FailedAnnotationRequestResult(AnnotationKey.NcbiSummary, "rs1");
            planRunner.Notify(ncbiResult);

            Assert.AreEqual(AnnotationRequestStatus.Finished, this.annotations[AnnotationKey.GoogleSearch].Status);
            this.GetTestKeys()
                .Skip(1)        //NOTE: depends on defined order of test keys - google search is the first
                .Select(key => annotations[key])
                .ForEach(info => Assert.AreEqual(AnnotationRequestStatus.Failed, info.Status));
        }

        private IEnumerable<AnnotationKey> GetTestKeys()
        {
            return new[] { AnnotationKey.GoogleSearch, AnnotationKey.NcbiSummary, AnnotationKey.Publications, AnnotationKey.PubMedSearch };
        }
    }
}
